package com.rgbgame.ui;

import org.jbox2d.collision.AABB;
import org.jbox2d.common.Vec2;

import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PGraphics3D;

/**
 * A custom fixed-width console class
 *
 */
public class RGBConsole {
	/** Size of the wraparound line buffer */
	static final private int BUFFER_SIZE = 1000;
	
	/**
	 * The text in the console.
	 */
	private String[] m_buffer;
	
	/**
	 * The console buffer uses a wraparound array; m_lineOffset
	 * is the location where the next item should be inserted,
	 * which means it points to the oldest element in the array.
	 * As m_lineOffset goes up, generally the lines are newer.
	 */
	private int m_lineOffset;
	
	/**
	 * Number of lines we are scrolled up.
	 */
	private int m_scrollBack;
	
	/**
	 * The position of the console in screen coordinates.
	 */
	private AABB m_rect;
	
	/** Is the console visible? */
	private boolean m_visible;
	
	/** The vertical amount to move per line. */
	private float m_fontHeight;
	/** The horizontal amount to move per character. */
	private float m_fontWidth;
	
	/** Console width in characters; must match up with m_fontWidth and m_rect dimensions. */
	private int m_widthChars;
	/** Console height in characters; must match up with m_fontHeight and m_rect dimensions. */
	private int m_heightChars;

	private PFont m_font;
	private PApplet m_pApplet;
	
	public RGBConsole(PApplet pApplet, float border) {
		this(pApplet, new AABB(new Vec2(border,border), new Vec2(pApplet.width-border, pApplet.height-border)));
	}
	
	public RGBConsole(PApplet pApplet) {
		// Default 2% border
		this(pApplet, pApplet.width*.02f);
	}
	
	public RGBConsole(PApplet pApplet, AABB aabb) {
		m_pApplet = pApplet;
		m_visible = true;
		m_font = m_pApplet.createFont("Courier",12);//"LucidaGrande-Bold",12);//-Bold-14.vlw");
		m_pApplet.textFont(m_font);
		if (m_pApplet.g instanceof PGraphics3D) m_pApplet.textMode(PApplet.SCREEN);
		m_fontHeight = 14.0f;
		m_fontWidth = 7.0f;
		m_rect = aabb;
		m_widthChars = (int)((m_rect.upperBound.x-m_rect.lowerBound.x)/m_fontWidth);
		m_heightChars = (int)((m_rect.upperBound.y-m_rect.lowerBound.y)/m_fontHeight);
		m_buffer = new String[BUFFER_SIZE];
		for (int i=0; i<BUFFER_SIZE; ++i) {
			m_buffer[i] = "";
		}
	}
	
	public void draw() {
		if (!m_visible) return;
		float currY = m_rect.upperBound.y;// - this.m_fontHeight*.5f;
		for (int i=0; i<m_heightChars; ++i) {
			String s = getLine(i+m_scrollBack);
			float currX = m_rect.lowerBound.x;
			for (int j = 0; j<s.length(); ++j) {
				m_pApplet.text(s.charAt(j),currX,currY);
				currX += m_fontWidth;
			}
			currY -= m_fontHeight;
		}
	}
	
	/**
	 * Output a string and a return to the RGBConsole.
	 * @param s
	 */
	public void println(String s) {
		String[] split = s.split("\n");
		for (int i=0; i<split.length; ++i) {
			int endIndex = Math.min(split[i].length(),m_widthChars);
			String newS = split[i].substring(0, endIndex);
			String remS = split[i].substring(endIndex,split[i].length());
			while(newS.length() > 0) {
				addLineToBuffer(newS);
				if (remS.length() == 0) break;
				endIndex = Math.min(remS.length(),m_widthChars);
				newS = remS.substring(0, endIndex);
				remS = remS.substring(endIndex,remS.length());
			}
		}
	}
	
	private void addLineToBuffer(String s) {
		m_buffer[m_lineOffset] = s;
		++m_lineOffset;
		if (m_lineOffset == BUFFER_SIZE) m_lineOffset = 0;
	}
	
	/**
	 * Gets the line n-th from the front of the line -
	 * you can't use the m_buffer array itself because
	 * it wraps around.
	 * <BR><BR>
	 * Garbage results if n is less than zero or greater
	 * than BUFFER_SIZE.
	 * @param n The n-th newest string to get
	 * @return
	 */
	private String getLine(int n) {
		if (n >= BUFFER_SIZE) return "";
		if (n < 0) return "";
		int tmp = m_lineOffset - 1 - n;
		while(tmp < 0) {
			tmp += BUFFER_SIZE;
		}
		while (tmp >= BUFFER_SIZE) {
			tmp -= BUFFER_SIZE;
		}
		return m_buffer[tmp];
	}
	
	/**
	 * Get the non-empty contents of the console.
	 * @return
	 */
	public String[] getContents() {
		int lines = 0;
		for (int i=0; i<BUFFER_SIZE; ++i) {
			if (!getLine(i).equals("")) ++lines; 
		}
		String[] result = new String[lines];
		int count = 0;
		for (int i=0; i<BUFFER_SIZE; ++i) {
			if (!getLine(i).equals("")) {
				result[lines-1-count] = getLine(i);
				++count;
			}
		}
		return result;
	}
	
	public void saveFile(String filename) {
		m_pApplet.saveStrings(filename, getContents());
		println("Console dump saved to "+filename);
	}
	
	public void setVisible(boolean isVisible) {
		m_visible = isVisible;
	}
	
	public boolean isVisible() {
		return m_visible;
	}
}
